package cn.fl.login.controller;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.ServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import cmm.comm.facade.framework.api.ISysCtrlCfgApiService;
import cmm.comm.facade.framework.condition.SysCtrlCfgQueryCondition;
import cmm.mid.core.framework.dto.DataResultDTO;
import cmm.multi.redis.service.IMultiRedisService;
import cmm.user.facade.system.constant.LoginCacheConstant;
import cmm.user.facade.system.constant.SysUsrConstant;
import cmm.user.facade.system.constant.SysUsrDeviceBindConstant;
import cmm.user.facade.system.dto.SysUsrScanDTO;
import cn.cmm.base.framework.context.ApplicationContextAccessor;
import cn.cmm.base.framework.exception.BaseException;
import cn.cmm.base.framework.utils.*;
import cn.cmm.cache.framework.utils.PropertiesCacheUtils;
import cn.fl.framework.base.constant.WebBaseConstant;
import cn.fl.framework.constant.DictionaryConstant;
import cn.fl.login.loginEnum.CtrlUsrLoginEnum;
import cn.fl.login.utils.UUIDUtils;
import cn.fl.system.service.ISysDictionaryService;
import cn.fl.system.service.ISysUsrService;
import cn.fl.system.vo.SysDictionaryVO;
import cn.lionbridge.center.api.ILoginAuthApiService;
import cn.lionbridge.center.utils.HttpIpUtils;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import org.apache.commons.lang.ArrayUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import cmm.mid.core.framework.page.DataResultVO;
import cmm.web.core.framework.controller.BaseController;
import cn.cmm.base.framework.constant.BaseConstant;
import cn.fl.framework.base.context.CurrentThreadContext;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Controller
@RequestMapping(value = "/login/login")
public class LoginController extends BaseController {

	@SuppressWarnings("unused")
	private static final Logger logger = LoggerFactory.getLogger(LoginController.class);

	public static final String QRCODE_CONTENT_URL = PropertiesUtils.getProperty("qrcode.qrcode.properties.content.url");

	/**
	 * 缓存集群服务
	 */
	@Resource(name = "userRedisService")
	private IMultiRedisService userRedisService;

	@Autowired
	private ISysUsrService sysUsrService;

	@Autowired
	private ISysDictionaryService sysDictionaryService;

	@Autowired
	private ISysCtrlCfgApiService sysCtrlCfgApiService;

	@Autowired
	private ILoginAuthApiService loginAuthApiService;

	/**
	 * 跳转登录页
	 */
	@RequestMapping(value = "/toLoginPage.do")
	public ModelAndView toLoginPage(HttpServletRequest request, HttpServletResponse response) throws IOException {

		ModelAndView modelAndView = new ModelAndView("login/login");
		modelAndView.addObject("loginType", CtrlUsrLoginEnum.PASSWORD.getValue());
		try {
			SysCtrlCfgQueryCondition qc = new SysCtrlCfgQueryCondition();
			qc.setSysCd(WebBaseConstant.SYS_SYS_CD);
			qc.setOrgCd(WebBaseConstant.SYS_P_ORG_CD);
			qc.setCtrlCode("CTRL_USR_0004");
			String code = sysCtrlCfgApiService.searchSysCtrlCfgByCtrlCode(qc);
			if(CtrlUsrLoginEnum.SCANCODE.getKey().equals(code)){
				modelAndView.addObject("loginType", CtrlUsrLoginEnum.SCANCODE.getValue());
			}
			if(CtrlUsrLoginEnum.ALL.getKey().equals(code)){
				modelAndView.addObject("loginType", CtrlUsrLoginEnum.ALL.getValue());
			}
			BaseLogUtils.info(logger, "toLoginPage", "获取用户登陆方式配置:" + code);
		} catch (BaseException e) {
			BaseLogUtils.error(logger, "toLoginPage", "获取用户登陆方式配置异常，" + e.getMessage(), e);
		} catch (Exception e) {
			BaseLogUtils.error(logger, "toLoginPage", "获取用户登陆方式配置异常，" + e.getMessage(), e);
		}
		String sqid = getCookieByName(request, "webSQID");
		if (StringUtils.isNotEmpty(sqid)) {
			String[] split = sqid.split("_");
			if (2 == split.length) {
				String userAgent = request.getHeader("User-Agent");
				String remoteIp = HttpIpUtils.getRemoteIp(request);
				userAgent = userAgent + "sqjt"+ remoteIp +"sqjt"+ WebBaseConstant.SYS_SYS_CD;
				DataResultDTO dataResultDTO = loginAuthApiService.authLogin(split[1], split[0],userAgent);
				if (null != dataResultDTO && dataResultDTO.getSuccess() == BaseConstant.IS_YESNO_YES) {
					response.sendRedirect(PropertiesCacheUtils.getProperty("web.web.properties.project")+"/login/login/toIndexPage.do");
					return null;
				}
			}
		}
		delCookie(response);
		String authServerPath = PropertiesCacheUtils.getProperty("web.web.properties.auth.server.path");
		request.getSession().setAttribute("authServerPath",authServerPath);
		return modelAndView;
	}
	private String getCookieByName(ServletRequest request, String name) {
		String cookieStr = "";
		Cookie[] cookies = ((HttpServletRequest) request).getCookies();
		if(ArrayUtils.isEmpty(cookies)){
			return cookieStr;
		}
		for (Cookie cookie : cookies) {
			if (cookie.getName().equals(name)) {
				cookieStr = cookie.getValue();
			}
		}
//		if(StringUtils.isNotEmpty(cookieStr)){
//			return DESedeEncrypt.decrypt(cookieStr);
//		}
		return cookieStr;
	}
	private void delCookie(HttpServletResponse response){
		Cookie newCookie=new Cookie("webSQID",null); //假如要删除名称为username的Cookie
		newCookie.setMaxAge(0); //立即删除型
		newCookie.setPath("/"); //项目所有目录均有效，这句很关键，否则不敢保证删除
		response.addCookie(newCookie);
	}
	@RequestMapping(value = "/toMainPage.do")
	public ModelAndView toMainPage(HttpServletRequest request, HttpServletResponse response) {
		return new ModelAndView("main/main/main");
	}
	
	/**
	 * 跳转首页
	 */
	@RequestMapping(value = "/toIndexPage.do")
	public ModelAndView toIndexPage(HttpServletRequest request, HttpServletResponse response) {
		String authServerPath = PropertiesCacheUtils.getProperty("web.web.properties.auth.server.path");
		request.getSession().setAttribute("authServerPath",authServerPath);
		return new ModelAndView("index");
	}

	/**
	 * 跳转首页
	 */
	@RequestMapping(value = "/toPowerErrorPage.do")
	public ModelAndView toPowerErrorPage(HttpServletRequest request, HttpServletResponse response) {
		return new ModelAndView("powerError");
	}


	@RequestMapping(value = "/loginout.do")
	@ResponseBody
	public Object loginout(HttpServletRequest request, HttpServletResponse response) {
		this.usrExit(request,response);
		DataResultVO result = new DataResultVO(BaseConstant.IS_YESNO_YES,"操作成功!");
		return result;
	}

	/**
	 * @MethodName usrExit
	 * @Description: 用户退出
	 * @Author: wangpengtao@lionbridgecapital.cn
	 * @CreateDate: 2019/12/11 10:56
	 * @Version: V1.0.0
	 * @Param request
	 * @Param response
	 * @Return void
	 * @UpdateRemark [序号][YYYY-MM-DD] [更改人姓名][变更描述]
	 */
	private void usrExit(HttpServletRequest request, HttpServletResponse response){
		HttpSession session = request.getSession(true);
		CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_USER_ID, null);
		CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_USER_NAME, null);
		CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_USER_INFO, null);
		CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_ROLE_NM, null);
		CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_ORG_NM, null);
		CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_ORG_CD, null);
		CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_ROLE_ID, null);
		CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_ORG_ID, null);
		CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_ORG_SHT_NM, null);
		CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_ORG_DISP_NM, null);
		CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_ROLE_GRP_ID, null);
		CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_ORG_TYP_CD, null);
		CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_ORG_RGN_CD_NM, null);
		CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_ROLE_GRP_ID, null);
		CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_RES_POWER_URL, null);

		session.setAttribute(CurrentThreadContext.CURRENT_USER_ID, null);
		session.setAttribute(CurrentThreadContext.CURRENT_USER_NAME, null);
		session.setAttribute(CurrentThreadContext.CURRENT_USER_INFO, null);
		session.setAttribute(CurrentThreadContext.CURRENT_ORG_CD, null);
		session.setAttribute(CurrentThreadContext.CURRENT_ROLE_ID, null);
		session.setAttribute(CurrentThreadContext.CURRENT_ROLE_NM, null);
		session.setAttribute(CurrentThreadContext.CURRENT_ORG_NM, null);
		session.setAttribute(CurrentThreadContext.CURRENT_ORG_ID, null);
		session.setAttribute(CurrentThreadContext.CURRENT_ORG_SHT_NM, null);
		session.setAttribute(CurrentThreadContext.CURRENT_ORG_DISP_NM, null);
		session.setAttribute(CurrentThreadContext.CURRENT_ROLE_GRP_ID, null);
		session.setAttribute(CurrentThreadContext.CURRENT_ORG_TYP_CD, null);
		session.setAttribute(CurrentThreadContext.CURRENT_ORG_RGN_CD, null);
		session.setAttribute(CurrentThreadContext.CURRENT_ORG_RGN_CD_NM, null);
		session.setAttribute(CurrentThreadContext.CURRENT_RES_POWER_URL, null);

		Subject user = SecurityUtils.getSubject();
		user.logout();
	}

	/**
	 * @MethodName ImageCaptcha
	 * @Description: 生成随机验证码图片
	 * @Author: wangpengtao@lionbridgecapital.cn
	 * @CreateDate: 2019/2/28 9:40
	 * @Version: V1.0.0
	 * @Param request
	 * @Param response
	 * @Param model
	 * @Return void
	 * @UpdateRemark [序号][YYYY-MM-DD] [更改人姓名][变更描述]
	 */
	@RequestMapping(value = "/kaptcha.do", method = { RequestMethod.GET})
	@ResponseBody
	public Object ImageCaptcha(HttpServletRequest request, HttpServletResponse response){
		DataResultVO result = new DataResultVO(BaseConstant.IS_YESNO_YES, "获取成功");

		try {
			response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
			response.setHeader("Cache-Control", "no-store");
			response.setHeader("Pragma", "no-cache");
			response.setDateHeader("Expires", 0);
			response.setContentType("image/jpeg");
			String usrNm = request.getParameter("usrNm");

			if (StringUtils.isBlank(usrNm)) {
				result.setSuccess(BaseConstant.IS_YESNO_NO);
				result.setInfo("请输入用户名称！");
				return result;
			}

			String verifyCode = VerifyCodeUtil.generateVerifyCode(4);
			//存入会话session
			userRedisService.setex("WEBVerifyImg"+usrNm,300,verifyCode.toLowerCase());
			//生成图片
			int w = 200, h = 80;
			VerifyCodeUtil.outputImage(w, h, response.getOutputStream(), verifyCode);

		} catch (IllegalArgumentException e) {
			throw new BaseException("生成验证码失败，请重试");
		} catch (IOException e) {
			throw new BaseException("生成验证码失败，请重试");
		}
		return result;
	}

	/**
	 * @MethodName getAuthCd
	 * @Description: 获取短信验证码信息
	 * @Author: wangpengtao@lionbridgecapital.cn
	 * @CreateDate: 2019/3/1 15:32
	 * @Version: V1.0.0
	 * @Param request
	 * @Param response
	 * @Return java.lang.Object
	 * @UpdateRemark [序号][YYYY-MM-DD] [更改人姓名][变更描述]
	 */

	@RequestMapping(value = "/getAuthCd.do", method = { RequestMethod.GET})
	@ResponseBody
	public Object getAuthCd(HttpServletRequest request, HttpServletResponse response) throws BaseException {
		BaseLogUtils.info(logger, "getAuthCd", "获取短信验证码处理开始");
		String usrNm = request.getParameter("usrNm");
		String verifyImg = request.getParameter("verifyImg");
		DataResultVO result = new DataResultVO(BaseConstant.IS_YESNO_YES, "获取成功");
		try {
			if (StringUtils.isBlank(usrNm)) {
				result.setSuccess(BaseConstant.IS_YESNO_NO);
				result.setInfo("请输入用户名称！");
				return result;
			}
			//缓存时间长度
			int catchSeconds = 600; //10 分钟内发送次数大于3
			//发送次数超过次数将展示图片验证码
			int catchTimes = 3;
			//短信发送编号
			String msgCode = SysUsrConstant.USR_CHECK_CODE+"";
			String onOff=this.sysUsrService.getCtrlUsrLogin();
			if(BaseConstant.IS_YESNO_NO_STR.equals(onOff)){
				BaseLogUtils.info(logger, "getAuthCd", usrNm + "当前验证码开关为关闭状态");
				result.setSuccess(3);
				result.setInfo("短信验证码功能未开启，您可通过用户名密码直接登录！");
				return result;
			}

			List<SysDictionaryVO> dictList = sysDictionaryService.searchGroup(DictionaryConstant.CODE_FL_LOGIN_CD,CurrentThreadContext.getCurrentSysCd(),"0000");
			if (CollectionUtils.isNotEmpty(dictList)) {
				for (SysDictionaryVO dictVO : dictList) {
					//获取缓存时间
					if (LoginCacheConstant.LOGIN_MSG_CATCH_DATE_KEY.equals(dictVO.getCode())) {
						if (StringUtils.isNotEmpty(dictVO.getCodeNm())) {
							catchSeconds = Integer.parseInt(dictVO.getCodeNm());
						}
						//获取缓存次数
					} else if (LoginCacheConstant.LOGIN_MSG_CATCH_TIMES_KEY.equals(dictVO.getCode())) {
						if (StringUtils.isNotEmpty(dictVO.getCodeNm())) {
							catchTimes = Integer.parseInt(dictVO.getCodeNm());
						}
					}
				}
			}

			String redisTimesName = "WEBSENDMESS" + usrNm + "TIMES";
			//从redis中获取请求次数
			Object objTimes = userRedisService.get(redisTimesName);
			if (null == objTimes) {
				userRedisService.setex(redisTimesName, catchSeconds, 1);
				result.setData(BaseConstant.IS_YESNO_NO);
			} else {
				int times = (int) objTimes;
				BaseLogUtils.info(logger, "getAuthCd", usrNm + "已获验证码次数：" + times);

				//如果等于3次，返回展示验证码信息
				if (catchTimes == times) {
					result.setData(BaseConstant.IS_YESNO_YES);
					//如果大于3次要求图片验证码正确切返回展示验证码信息
				} else if (times > catchTimes) {
					result.setData(BaseConstant.IS_YESNO_YES);
					if (StringUtils.isEmpty(verifyImg)) {
						result.setSuccess(BaseConstant.IS_YESNO_NO);
						result.setInfo("请输入图片验证码！");
						return result;
					}
					Object objVerifyImg = userRedisService.get("WEBVerifyImg" + usrNm);
					if (null == objVerifyImg) {
						result.setSuccess(BaseConstant.IS_YESNO_NO);
						result.setInfo("图片验证码已过期，请更新后重试！");
						return result;
					}
					String strVerifyImg = objVerifyImg.toString();
					if (!verifyImg.toLowerCase().equals(strVerifyImg.toLowerCase())) {
						result.setSuccess(BaseConstant.IS_YESNO_NO);
						result.setInfo("图片验证码错误，请重新输入！");
						return result;
					}
				} else {
					result.setData(BaseConstant.IS_YESNO_NO);
				}
				BaseLogUtils.info(logger, "getAuthCd", usrNm + "已获取短信次数为:" + times);
				userRedisService.setex(redisTimesName, catchSeconds, times + 1);
			}
			DataResultDTO dataResultDTO = this.sysUsrService.getAuthCdByUsrNm(usrNm, msgCode);
			if(null == dataResultDTO){
				result.setSuccess(BaseConstant.IS_YESNO_NO);
				result.setInfo("获取短信验证码失败，请重新获取！");
			}else {
				BaseLogUtils.info(logger, "getAuthCd", "获取短信验证码结果:"+dataResultDTO.getSuccess());
				result.setSuccess(dataResultDTO.getSuccess());
				result.setInfo(dataResultDTO.getInfo());
			}
		} catch (BaseException ex) {
			result.setSuccess(BaseConstant.IS_YESNO_NO);
			result.setInfo(ex.getMessage());
			BaseLogUtils.error(logger, "getAuthCd", ex.getMessage(), ex);
		} catch (Exception ex) {
			result.setSuccess(BaseConstant.IS_YESNO_NO);
			result.setInfo("获取短信验证码失败，请重新获取！");
			BaseLogUtils.error(logger, "getAuthCd", ex.getMessage(), ex);
		}
		BaseLogUtils.info(logger, "getAuthCd", "获取短信验证码处理结束");
		return result;
	}


    /**
     * 生成登陆二维码
     * @methodName createQrcode
     * @author: menghongqiang@lionbridgecapital.cn
     * @createDate: 2020/4/27 11:00
	 * @version: V1.0.0
	 * @param
	 * @Return java.lang.Object
	 * @updateRemark [序号][YYYY-MM-DD] [更改人姓名][变更描述]
	 */
	@RequestMapping(value = "/createQrcode.do", method = { RequestMethod.POST})
	@ResponseBody
	public Object createQrcode(String osName){
        DataResultVO result = new DataResultVO(BaseConstant.IS_YESNO_YES, "获取成功");
        try {
        	if(StringUtils.isBlank(osName)){
        		osName = "Unknown";
			}
            String qrcodeId = UUIDUtils.uuid();
			String content = QRCODE_CONTENT_URL + "?pageNum=1001" + "&osName=" + osName + "&pcToken=" + qrcodeId;
			//生成二维码
            String dataUrl = generateQrCode(content);

            Map<String, String> map = new HashMap<>();
            map.put("qrcodeId", qrcodeId);
            map.put("dataUrl", dataUrl);
            result.setData(map);

            //存入会话session
            String redisKey = getQrCodeRedisKey(qrcodeId);
            SysUsrScanDTO sysUsrScanDTO = new SysUsrScanDTO();
            sysUsrScanDTO.setState(SysUsrDeviceBindConstant.SYS_USR_SCAN_0);
            sysUsrScanDTO.setSysCd(WebBaseConstant.SYS_SYS_CD);
            userRedisService.setex(redisKey, SysUsrDeviceBindConstant.redisTime, sysUsrScanDTO);
        } catch (Exception ex) {
            result.setSuccess(BaseConstant.IS_YESNO_NO);
            result.setInfo("二维码生成失败");
            BaseLogUtils.error(logger, "createQrcode", ex.getMessage(), ex);
        }
        return result;
	}


    /**
     * 判断二维码是否已登录
     * @methodName checkQrcodeIsLogined
     * @author: menghongqiang@lionbridgecapital.cn
     * @createDate: 2020/4/27 11:00
     * @version: V1.0.0
     * @param qrcodeId
     * @Return java.lang.Object
     * @updateRemark [序号][YYYY-MM-DD] [更改人姓名][变更描述]
     */
    @RequestMapping(value = "/isLogined.do", method = { RequestMethod.POST})
    @ResponseBody
    public Object checkQrcodeIsLogined(String qrcodeId){
        if (StringUtils.isBlank(qrcodeId)) {
            return new DataResultVO(BaseConstant.IS_YESNO_NO, "二维码Id不能为空");
        }
        DataResultVO result = new DataResultVO(BaseConstant.IS_YESNO_YES, "获取成功");
        try {
            String redisKey =  getQrCodeRedisKey(qrcodeId);
            SysUsrScanDTO sysUsrScanDTO = (SysUsrScanDTO) userRedisService.get(redisKey);
			if(sysUsrScanDTO == null){
				sysUsrScanDTO = new SysUsrScanDTO();
			}
			Map<String, Object> map = new HashMap<>();
			String state = sysUsrScanDTO.getState();
			map.put("code", state);
			if(SysUsrDeviceBindConstant.SYS_USR_SCAN_0.equals(state)){
				map.put("msg","二维码未扫描，请扫描二维码");
			} else if(SysUsrDeviceBindConstant.SYS_USR_SCAN_1.equals(state)){
				map.put("msg","请手机客户端确认登录");
			} else if(SysUsrDeviceBindConstant.SYS_USR_SCAN_2.equals(state)){
				map.put("msg","二维码已取消授权");
			} else if(SysUsrDeviceBindConstant.SYS_USR_SCAN_3.equals(state)){
				map.put("msg","手机客户端授权成功");
			}else {
				map.put("code", SysUsrDeviceBindConstant.SYS_USR_SCAN_4);
				map.put("msg","二维码过期，请重新扫描");
			}
            result.setData(map);
        } catch (Exception ex) {
            result.setSuccess(BaseConstant.IS_YESNO_NO);
            result.setInfo("获取失败");
            BaseLogUtils.error(logger, "createQrcode", ex.getMessage(), ex);
        }
        return result;
    }

    /**
     * 生成二维码
     * @param content
     * @return
     * @throws Exception
     */
	private String generateQrCode(String content) throws Exception {
        QRCodeWriter writer = new QRCodeWriter();
        BitMatrix bt  = writer.encode(content, BarcodeFormat.QR_CODE, 200, 200);
        BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bt);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage,"png",outputStream);
        String encode = Base64Utils.encodeToString(outputStream.toByteArray());
        String dataUrl = "data:image/png;base64,"+encode;
        return dataUrl;
    }

    /**
     * 生成二维码RedisKey
     * @param key
     * @return
     */
    private String getQrCodeRedisKey(String key){
        return SysUsrDeviceBindConstant.USR_SCAN_RED + WebBaseConstant.SYS_SYS_CD + ":" + key;
    }
}